using System.Collections.Generic;
using Game.Networking.Utils;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

namespace Game.UI {
	public class UnitStatusWindow : UIWindow {
		public TMP_Text      Title;
		public Button        OpenTerminalButton;
		public Button        RecompileButton;
		public Button        LinkFolderButton;
		public Button        UploadButton;
		public Button        DownloadButton;
		public Button        NewFileButton;
		public RectTransform FileListRoot;

		public Image    StatusIcon;
		public TMP_Text StatusText;

		public Sprite StatusIconActive;
		public Sprite StatusIconPause;
		public Sprite StatusIconError;
		public Sprite StatusIconUnknown;
		public Sprite StatusIconBusy;

		public ProgramFileItem FileItemFab;

		List<ProgramFileItem> _fileItems = new List<ProgramFileItem>();

		string                         _selectedFileName;
		IComputingUnitUserDataProvider _dataProvider;


		protected override void Awake() {
			base.Awake();
			OpenTerminalButton.onClick.AddListener(OnOpenTerminalClick);
			RecompileButton.onClick.AddListener(OnRecompileClick);
			LinkFolderButton.onClick.AddListener(OnLinkFolderClick);
			UploadButton.onClick.AddListener(OnUploadButtonClick);
			DownloadButton.onClick.AddListener(OnDownloadButtonClick);
			NewFileButton.onClick.AddListener(ShowAddFileDialog);
			FileItemFab.gameObject.SetActive(false);

			var isServer = NetworkOptions.StartServer;
			if ( isServer ) {
				_dataProvider = new ServerComputingUnitUserDataProvider();
			}
			else {
				_dataProvider = new ClientComputingUnitUserDataProvider();
			}
		}

		private void OnLinkFolderClick() {
		}

		private void OnEnable() {
			var files = _dataProvider?.GetCodeFiles();
			SetupFileList(files);
			SetupUnitStatus();
		}

		private void Start() {
			_dataProvider?.OnCodeFileListUpdated?.Subscribe(this, SetupFileList);
			_dataProvider?.OnCodeFileUpdated?.Subscribe(this, OnCodeFileUpdated);
			_dataProvider?.OnUnitStateChanged?.Subscribe(this, SetupUnitStatus);
			SetupUnitStatus();
		}

		void SetupUnitStatus() {
			var curStatus = _dataProvider.GetCurrentUnitState();
			switch ( curStatus ) {
				case ComputingUnitState.Active:
					StatusText.text = "Active";
					StatusIcon.sprite = StatusIconActive;
					break;
				case ComputingUnitState.Compilation:
				case ComputingUnitState.DomainCreated:
				case ComputingUnitState.RecompileRequest:
				case ComputingUnitState.RecompileRequestNoSave:
					StatusText.text = "Reload";
					StatusIcon.sprite = StatusIconBusy;
					break;
				case ComputingUnitState.BudgetExceeded:
				case ComputingUnitState.CompileError:
				case ComputingUnitState.RuntimeError:
					StatusText.text = "Error";
					StatusIcon.sprite = StatusIconError;
					break;
				case ComputingUnitState.Paused:
				case ComputingUnitState.NoTargetEntity:
					StatusText.text = "Idle";
					StatusIcon.sprite = StatusIconPause;
					break;
				case ComputingUnitState.Uninitialized:
				default:
					StatusText.text = "Unknown";
					StatusIcon.sprite = StatusIconUnknown;
					break;
			}
		}

		void SetupFileList() {
			SetupFileList(_dataProvider.GetCodeFiles());
		}

		void SetupFileList(List<string> files) {
			ClearFileList();
			if ( files == null ) {
				return;
			}

			foreach ( string file in files ) {
				var item = Instantiate(FileItemFab, FileListRoot, false);
				item.Setup(file, _dataProvider.IsCodeFileDownloaded(file), file == _selectedFileName, this);
				item.gameObject.SetActive(true);
				_fileItems.Add(item);
			}
		}

		void OnCodeFileUpdated(string fileName) {
			if ( string.IsNullOrEmpty(fileName) ) {
				return;
			}

			SetupFileItem(fileName);
		}

		void ClearFileList() {
			foreach ( var item in _fileItems ) {
				Destroy(item.gameObject);
			}

			_fileItems.Clear();
		}

		public void SetSelectedFile(string filename) {
			if ( string.IsNullOrEmpty(filename) ) {
				return;
			}

			if ( !_dataProvider.IsCodeFileDownloaded(filename) ) {
				_dataProvider.TryDownloadCodeFile(filename);
				return;
			}

			_selectedFileName = filename;
			var w = (CodeEditorWindow)UIHolder.Instance.GetWindow(WindowType.ProgramWindow);
			if ( w ) {
				var contents = _dataProvider.GetFileContents(filename);
				w.ShowWindow(filename, contents);
			}

			;
			ResetupFileItems();
		}

		void ResetupFileItems() {
			foreach ( var item in _fileItems ) {
				item.Setup(item.FileName, _dataProvider.IsCodeFileDownloaded(item.FileName),
					item.FileName == _selectedFileName, this);
			}
		}

		void SetupFileItem(string fileName) {
			if ( string.IsNullOrEmpty(fileName) ) {
				return;
			}

			foreach ( var item in _fileItems ) {
				if ( item.FileName == fileName ) {
					item.Setup(fileName, _dataProvider.IsCodeFileDownloaded(fileName), fileName == _selectedFileName,
						this);
					return;
				}
			}

			var newItem = Instantiate(FileItemFab, FileListRoot, false);
			newItem.Setup(fileName, true, fileName == _selectedFileName, this);
			newItem.gameObject.SetActive(true);
			_fileItems.Add(newItem);
		}

		public void ShowRemoveFileDialog(string filename) {
			if ( string.IsNullOrEmpty(filename) ) {
				return;
			}

			UIHolder.Instance.ShowNoticeWindow("Remove File", $"Are you sure you want to remove {filename}?", true,
				() => {
					_dataProvider.TryRemoveFile(filename);
				}, () => { });
		}

		public void ShowAddFileDialog() {
			var w = UIHolder.Instance.GetWindow(WindowType.CreateFileWindow);
			w.ShowWindow();
		}

		public void OnRecompileClick() {
			_dataProvider.SendRecompileRequest();
		}

		public void OnOpenTerminalClick() {
			UIHolder.Instance.ShowWindow(WindowType.ShipConsoleWindow);
		}

		void OnUploadButtonClick() {
			_dataProvider.UploadFiles();
		}

		void OnDownloadButtonClick() {
			_dataProvider.DownloadFiles();
		}
	}
}